/**
 * Copyright (c) 2018 开源 All rights reserved.
 * <p>
 * https://www.sxyc.io
 * <p>
 * 版权所有，侵权必究！
 */

package io.renren.controller;

import cn.hutool.core.util.ObjectUtil;
import io.renren.annotation.Login;
import io.renren.common.constant.Constant;
import io.renren.common.page.PageData;
import io.renren.common.utils.Result;
import io.renren.common.validator.ValidatorUtils;
import io.renren.common.validator.group.AddGroup;
import io.renren.common.validator.group.DefaultGroup;
import io.renren.modules.yckj.common.ThreadLocalUtil;
import io.renren.modules.yckj.dto.*;
import io.renren.modules.yckj.entity.InvoiceLogsEntity;
import io.renren.modules.yckj.entity.OrderEntity;
import io.renren.modules.yckj.entity.TeamRelationEntity;
import io.renren.modules.yckj.enums.status.AuthenticationStatus;
import io.renren.modules.yckj.enums.status.CommonStatus;
import io.renren.modules.yckj.enums.status.OrderStatus;
import io.renren.modules.yckj.enums.type.MachineType;
import io.renren.modules.yckj.enums.type.PayWay;
import io.renren.modules.yckj.enums.type.QueryType;
import io.renren.modules.yckj.service.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 测试接口
 *
 * @author Mark sunlightcs@gmail.com
 */
@RestController
@RequestMapping("/yckj/order")
@Tag(name = "订单接口")
@AllArgsConstructor
public class ApiOrderController {

    private final OrderService orderService;
    private final TeamRelationService teamRelationService;
    private final ProjectService projectService;
    private final TeamService teamService;
    private final InvoiceLogsService invoiceLogsService;
    private final MachineService machineService;

    @Login
    @GetMapping("list")
    @Operation(summary = "根据状态获取我的订单列表：status不传全部")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "status", description = "状态", required = true)
    public Result<List<OrderDTO>> list(@RequestParam("status") Integer status) {
        Map<String, Object> map = new HashMap<>();
        map.put("userId", ThreadLocalUtil.getUserId());
        map.put("status", status > -1 ? status : null);
        List<OrderDTO> dtoList = orderService.getOrderList(map);
        return new Result<List<OrderDTO>>().ok(dtoList);
    }

    @Login
    @GetMapping("page")
    @Operation(summary = "根据状态分页获取我的订单列表：status不传全部")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "status", description = "状态", required = true)
    @Parameters({
            @Parameter(name = Constant.PAGE, description = "当前页码，从1开始", required = true),
            @Parameter(name = Constant.LIMIT, description = "每页显示记录数", required = true),
            @Parameter(name = Constant.ORDER_FIELD, description = "排序字段"),
            @Parameter(name = Constant.ORDER, description = "排序方式，可选值(asc、desc)")
    })
    public Result<PageData<OrderDTO>> page(@RequestParam Map<String, Object> params) {
        Object status = params.get("status");
        params.put("userId", ThreadLocalUtil.getUserId());
        params.put("status", ObjectUtil.isAllNotEmpty(status) ? status : null);
        PageData<OrderDTO> page = orderService.pageForApi(params);
        return new Result<PageData<OrderDTO>>().ok(page);
    }

    @Login
    @PostMapping("save")
    @Operation(summary = "预约")
    public Result<Boolean> save(@RequestBody OrderDTO dto) throws Exception {
        //效验数据
        if (ThreadLocalUtil.getUser().getAuthentication().equals(AuthenticationStatus.YES.getCode())) {
            ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);
            dto.setUserId(ThreadLocalUtil.getUserId());
            dto.setUserName(ThreadLocalUtil.getUserName());
            dto.setCreateTime(new Date());
            dto.setUpdateTime(new Date());
            return orderService.validatorAppoint(dto);
        } else {
            return new Result<Boolean>().error("请先实名认证后，再预约");
        }
    }

    @Login
    @GetMapping("info")
    @Operation(summary = "获取信息")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "id", description = "主键", required = true)
    public Result<OrderDTO> info(@RequestParam("id") Long id) {
        OrderDTO dto = orderService.get(id);
        if (dto != null && dto.getUserId().equals(ThreadLocalUtil.getUserId())) {
            ProjectDTO projectDTO = projectService.get(dto.getProjectId());
            if (projectDTO != null)
                dto.setProjectImage(projectDTO.getImage());
            return new Result<OrderDTO>().ok(dto);
        } else {
            return new Result<OrderDTO>().error("暂无此订单信息");
        }
    }

    @Login
    @GetMapping("time")
    @Operation(summary = "获取当前机器的已预约时间")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "machineId", description = "机器Id", required = true)
    public Result<List<String>> time(@RequestParam("machineId") Long machineId) {
        List<String> times = new ArrayList<>();
        MachineDTO machineDTO = machineService.get(machineId);
        if (machineDTO != null && machineDTO.getType().equals(MachineType.YES.getCode())) {
            Map<String, Object> map = new HashMap<>();
            map.put("machineId", machineId);
            map.put("leStatus", OrderStatus.UNCONFIRMED.getCode());
            List<OrderDTO> orderDTOList = orderService.list(map);
            orderDTOList.forEach(orderDTO -> {
                if (orderDTO.getBookAllTimes() != null && !orderDTO.getBookAllTimes().isEmpty()) {
                    times.addAll(Arrays.asList(orderDTO.getBookAllTimes().split(",")));
                }
            });
        }
        return new Result<List<String>>().ok(times);
    }

    @Login
    @GetMapping("team/approve/list")
    @Operation(summary = "获取课题组预约审核订单列表")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "teamId", description = "课题组Id", required = true)
    public Result<List<OrderDTO>> teamApproveList(@RequestParam("teamId") Long teamId) {
        TeamRelationEntity dbTeamRelation = teamRelationService.getByTeamIdAndUserId(teamId, ThreadLocalUtil.getUserId());
        if (dbTeamRelation != null && dbTeamRelation.getApprove().equals(CommonStatus.YES.getCode())) {
            Map<String, Object> map = new HashMap<>();
            map.put("teamId", teamId);
            map.put("teamReview", CommonStatus.NO.getCode());
            List<OrderDTO> dtoList = orderService.getOrderList(map);
            return new Result<List<OrderDTO>>().ok(dtoList);
        } else {
            return new Result<List<OrderDTO>>().ok(new ArrayList<>());
        }
    }

    @Login
    @GetMapping("team/view/list")
    @Operation(summary = "获取课题组预约订单列表")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "teamId", description = "课题组Id", required = true)
    @Parameter(name = "type", description = "类型：0全部，1user", required = true)
    public Result<List<OrderDTO>> teamViewList(@RequestParam("teamId") Long teamId,
                                               @RequestParam("type") Integer type) {
        Map<String, Object> map = new HashMap<>();
        map.put("teamId", teamId);
        if (type.equals(QueryType.USER.getCode())) {
            map.put("userId", ThreadLocalUtil.getUserId());
        }
        List<OrderDTO> list = orderService.getOrderList(map);
        return new Result<List<OrderDTO>>().ok(list);
    }

    @Login
    @PostMapping("team/approve")
    @Operation(summary = "课题组预约审核")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "teamId", description = "课题组Id", required = true)
    @Parameter(name = "orderId", description = "订单Id", required = true)
    @Parameter(name = "status", description = "状态：1通过，2拒绝", required = true)
    public Result<Boolean> teamApprove(@RequestParam("teamId") Long teamId,
                                       @RequestParam("orderId") Long orderId,
                                       @RequestParam("status") Integer status
    ) throws Exception {
        TeamRelationEntity teamRelation = teamRelationService.getByTeamIdAndUserId(teamId, ThreadLocalUtil.getUserId());
        if (teamRelation != null && teamRelation.getApprove().equals(CommonStatus.YES.getCode())) {
            OrderDTO orderDTO = orderService.get(orderId);
            if (orderDTO != null) {
                boolean b = orderService.teamApprove(orderDTO, status, teamRelation);
                return new Result<Boolean>().ok(b);
            } else {
                return new Result<Boolean>().error("当前订单不存在！");
            }
        } else {
            return new Result<Boolean>().error("无审核权限！");
        }
    }

    @Login
    @PostMapping("sign")
    @Operation(summary = "签名确认")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "orderId", description = "订单Id", required = true)
    @Parameter(name = "signImage", description = "签字图片地址", required = true)
    public Result<Boolean> sign(@RequestParam("orderId") Long orderId,
                                @RequestParam("signImage") String signImage) {
        OrderDTO dbDto = orderService.get(orderId);
        boolean b = false;
        if (dbDto != null && dbDto.getUserId().equals(ThreadLocalUtil.getUserId())) {
            OrderEntity orderEntity = new OrderEntity();
            orderEntity.setId(orderId);
            orderEntity.setSign(CommonStatus.YES.getCode());
            orderEntity.setSignImage(signImage);
            orderEntity.setStatus(OrderStatus.WAIT_PAY.getCode());
            b = orderService.updateById(orderEntity);
            return new Result<Boolean>().ok(b);
        }
        return new Result<Boolean>().ok(b);
    }

    @Login
    @PostMapping("cancel")
    @Operation(summary = "订单取消")
    @Parameter(name = "orderId", description = "订单Id", required = true)
    public Result<Boolean> cancel(@RequestParam("orderId") Long orderId) throws Exception {
        OrderDTO dbDto = orderService.get(orderId);
        if (dbDto != null && dbDto.getStatus() < OrderStatus.FINISHED.getCode()
                && dbDto.getUserId().equals(ThreadLocalUtil.getUserId())) {
            boolean b = orderService.cancel(dbDto);
            return new Result<Boolean>().ok(b);
        } else {
            return new Result<Boolean>().error("当前订单不可取消！");
        }
    }

    @Login
    @PostMapping("balance/pay")
    @Operation(summary = "订单余额支付")
    @ApiResponse(content = @Content(mediaType = "application/json",
            schema = @Schema(implementation = OrderDTO.class)))
    @Parameter(name = "orderId", description = "订单Id", required = true)
    @Parameter(name = "payWay", description = "支付类型", required = true)
    public Result<Boolean> balancePay(@RequestParam("orderId") Long orderId, @RequestParam("payWay") Integer payWay) throws Exception {
        OrderDTO dbDto = orderService.get(orderId);
        if (dbDto != null && dbDto.getUserId().equals(ThreadLocalUtil.getUserId())) {
            boolean b = false;
            dbDto.setPayWay(payWay);
            if (dbDto.getTeamId() != null && dbDto.getTeamId() > 0) {
                TeamDTO teamDTO = teamService.get(dbDto.getTeamId());
                if (teamDTO != null) {
                    if (payWay.equals(PayWay.USER.getCode())) {
                        if (dbDto.getActualAmount().compareTo(ThreadLocalUtil.getUser().getBalance()) > 0) {
                            return new Result<Boolean>().error("当前个人余额不足！");
                        } else {
                            //组订单 个人余额支付
                            b = orderService.balancePayByUserForTeam(ThreadLocalUtil.getUserId(), dbDto);
                        }
                    } else if (payWay.equals(PayWay.TEAM.getCode())) {
                        if (dbDto.getActualAmount().compareTo(teamDTO.getBalance()) > 0) {
                            return new Result<Boolean>().error("当前组余额不足！");
                        } else {
                            //组订单 组余额支付
                            b = orderService.balancePayByTeam(teamDTO.getId(), dbDto);
                        }
                    }
                } else {
                    return new Result<Boolean>().error("当前组不存在！");
                }
            } else {
                //个人订单
                if (dbDto.getActualAmount().compareTo(ThreadLocalUtil.getUser().getBalance()) > 0) {
                    return new Result<Boolean>().error("当前个人余额不足！");
                } else {
                    //个人支付
                    b = orderService.balancePayByUser(ThreadLocalUtil.getUserId(), dbDto);
                }
            }
            return new Result<Boolean>().ok(b);
        } else {
            return new Result<Boolean>().error("当前订单不存在！");
        }
    }

    @Login
    @PostMapping("invoice/apply")
    @Operation(summary = "申请开票businessId(订单号), invoiceId,invoiceType,fileType,note")
    public Result<Boolean> applyInvoice(@RequestBody InvoiceLogsDTO invoiceLogsDTO) throws Exception {
        OrderDTO dbDto = orderService.get(invoiceLogsDTO.getBusinessId());
        if (dbDto != null
                && dbDto.getStatus().equals(OrderStatus.FINISHED.getCode())
                && dbDto.getUserId().equals(ThreadLocalUtil.getUserId())
                && dbDto.getPayWay().equals(PayWay.WX.getCode())) {
            InvoiceLogsEntity invoiceLogsEntity = invoiceLogsService.getByUserIdBusiness(ThreadLocalUtil.getUserId(), invoiceLogsDTO.getBusinessId(), invoiceLogsDTO.getBusinessType());
            if (invoiceLogsEntity != null) {
                //申请请开票
                invoiceLogsDTO.setId(invoiceLogsEntity.getId());
                boolean b = orderService.applyInvoice(dbDto, invoiceLogsDTO);
                return new Result<Boolean>().ok(b);

            } else {
                return new Result<Boolean>().error("当前订单无支付记录！");
            }
        } else {
            return new Result<Boolean>().error("当前订单不可申请开票！");
        }
    }

}